package be.ipl.finito.domaine;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;

import be.ipl.finito.exceptions.CaseOccupeeException;

@SuppressWarnings("serial")
@Entity
@Table(name = "PLATEAUX", schema = "FINITO")
public class Plateau implements Serializable {

	@Transient
	private int timerInactivite;

	@Transient
	private int score;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id_plateau;

	@NotNull
	@ManyToOne
	@JoinColumn(name = "PARTIE")
	private Partie partie;

	@NotNull
	@ManyToOne
	@JoinColumn(name = "JOUEUR")
	private Joueur joueur;

	@NotNull
	private int tourJoue;
	
	@Transient
	private List<Case> casesOccupees;

	@Transient
	private List<Jeton> jetonsAPoser;

	public Plateau(Joueur joueur, Partie partie) {
		this.joueur = joueur;
		this.partie = partie;
		tourJoue = 0;
		//initialisation
		casesOccupees = new ArrayList<Case>();
		jetonsAPoser = new ArrayList<Jeton>();
	}

	protected Plateau() {

	}

	public Plateau placerJeton(Jeton jeton, Case caseJeton)
			throws CaseOccupeeException {
		// TODO: catch l'exception
		for(Case c : casesOccupees) {
		if (c.getIndiceCaseJeton() == caseJeton.getIndiceCaseJeton())
			throw new CaseOccupeeException("la case choisie est deja occupee pas un autre jeton!");
		}
		
		if(jetonsAPoser.size() > 0)
		jetonsAPoser.remove(0);
		
		caseJeton.setJeton(jeton);
		casesOccupees.add(caseJeton);

		
		tourJoue++;

		return this;
	}

	public Case deplacerJeton(Jeton jeton, Case caseJeton)
			throws CaseOccupeeException {
		Case cases = null;
		for (Case c : casesOccupees) {
			if (c.getJeton().getNum() == jeton.getNum()) {
				casesOccupees.remove(c);
				cases = c;
				break;
			}
		}

		placerJeton(jeton, caseJeton);
		return cases;
	}

	public List<Jeton> calculerSuite() {
		if (casesOccupees.isEmpty()) {
			return new ArrayList<Jeton>();
		}

		List<Jeton> plusGrandeSuite = new ArrayList<Jeton>();
		List<Jeton> suiteTemporaire = new ArrayList<Jeton>();
		int maxTmp = -1;
		
		List<Jeton> casesOccupeesTrie = trierListeCase(casesOccupees);
				
		for(Jeton j: casesOccupeesTrie) {
			if (j.getNum() > maxTmp) {
				suiteTemporaire.add(j);
				maxTmp = j.getNum();
				
				if (suiteTemporaire.size() > plusGrandeSuite.size()) {
					plusGrandeSuite = new ArrayList<Jeton>(suiteTemporaire);
				}
				continue;
			}

			if (suiteTemporaire.size() > plusGrandeSuite.size()) {
				plusGrandeSuite = new ArrayList<Jeton>(suiteTemporaire);
			}
			suiteTemporaire = new ArrayList<Jeton>();
			suiteTemporaire.add(j);
			maxTmp = j.getNum();
		}

		return plusGrandeSuite;
	}

	private List<Jeton> trierListeCase(List<Case> casesOccupees) {

		List<Case> casesOccupeesTmp = new ArrayList<Case>(casesOccupees);
		List<Jeton> listeTrie = new ArrayList<Jeton>();
		for (int i = 0; i < this.casesOccupees.size(); i++) {
			Case caseTmp = null;
			for (Case c : casesOccupeesTmp) {

				if (caseTmp == null) {
					caseTmp = c;
				}

				if (c.getIndiceCaseJeton() < caseTmp.getIndiceCaseJeton()) {
					caseTmp = c;
				}
			}
			listeTrie.add(caseTmp.getJeton());
			casesOccupeesTmp.remove(caseTmp);
		}

		return listeTrie;
	}

	public void ajouterJetonAPoser(Jeton jeton) {
		jetonsAPoser.add(jeton);
	}
	
	public int getTimerInactivite() {
		return timerInactivite;
	}

	public void setTimerInactivite(int timerInactivite) {
		this.timerInactivite = timerInactivite;
	}

	public int getScore() {
		score = calculerSuite().size();
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}

	public Partie getPartie() {
		return partie;
	}

	public void setPartie(Partie partie) {
		this.partie = partie;
	}

	public Joueur getJoueur() {
		return joueur;
	}

	public void setJoueur(Joueur joueur) {
		this.joueur = joueur;
	}

	public List<Case> getCasesOccupees() {
		return casesOccupees;
	}

	public void setCasesOccupees(List<Case> casesOccupees) {
		this.casesOccupees = casesOccupees;
	}

	public List<Jeton> getJetonsAPoser() {
		return jetonsAPoser;
	}

	public void setJetonsAPoser(List<Jeton> jetonsAPoser) {
		this.jetonsAPoser = jetonsAPoser;
	}

	public int getIdPlateau() {
		return id_plateau;
	}

	public void removeJetonAPoser(Jeton jeton) {
		jetonsAPoser.remove(jeton);
	}
	
	public void addJetonAPoser(Jeton jeton) {
		jetonsAPoser.add(jeton);
	}
	
	
	public void setjetonsAPoserCalculer(Partie partie) {

		jetonsAPoser = new ArrayList<Jeton>();
				
		for(int i=0; i<partie.getIndiceTirage(); i++){
			jetonsAPoser.add(partie.getProchainJeton(i));
		}
		
		for(int i=0; i<casesOccupees.size(); i++) {
			for(int j=0; j<partie.getIndiceTirage(); j++) {
				if(jetonsAPoser.get(j).getNum() == casesOccupees.get(i).getJeton().getNum()) {
					jetonsAPoser.remove(j);
					break;
				}
				
			}
			
		}
		
	}
	
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id_plateau;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Plateau other = (Plateau) obj;
		if (id_plateau != other.id_plateau)
			return false;
		return true;
	}

	
	public int getTourJoue(){
		return this.tourJoue;
	}
}
